package com.ychong.library.view.largeimage

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import kotlinx.coroutines.GlobalScope
import java.io.InputStream


/**
 * 高清大图加载
 */
class LargeImageView : View {
    private var bitmap: Bitmap? = null
    private var scaleGestureDetector: ScaleGestureDetector? = null
    private var mDecoder: BitmapRegionDecoder? = null

    /**图片的宽和高*/
    private var mImageWidth: Int = 0
    private var mImageHeight: Int = 0

    private var mCurX: Float = -1f
    private var mCurY: Float = -1f

    private var mXDistance: Float = 0f
    private var mYDistance: Float = 0f

    private var mSpeed: Float = 1.0f

    private var mScale: Float = 1.0f

    companion object {
        /**绘制区域*/
        val mRect = Rect()

        val options: BitmapFactory.Options = BitmapFactory.Options()
    }

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
    constructor(context: Context, attributeSet: AttributeSet?, defStyle: Int) : super(
        context,
        attributeSet,
        defStyle
    ) {
        init()
    }

    private fun init() {
        //使用Bitmap.Config.RGB_565存储方式 一个像素占用两个字节
        options.inPreferredConfig = Bitmap.Config.RGB_565

        scaleGestureDetector = ScaleGestureDetector(context, scaleGestureListener)
    }

    private val scaleGestureListener =
        object : ScaleGestureDetector.OnScaleGestureListener {
            override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
                return true
            }

            override fun onScale(detector: ScaleGestureDetector?): Boolean {
                val scaleFactor = detector!!.scaleFactor
                mScale *= scaleFactor
                if (mScale < 0.8f) {
                    mScale = 0.8f
                }
                if (mScale > 3.0f) {
                    mScale = 2.0f
                }
                postInvalidate()
                return true
            }

            override fun onScaleEnd(detector: ScaleGestureDetector?) {

            }
        }


    fun setInputStream(inputStream: InputStream) {
        mDecoder = BitmapRegionDecoder.newInstance(inputStream, false)
        mImageWidth = mDecoder!!.width
        mImageHeight = mDecoder!!.height
        postInvalidate()
    }

    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
        scaleGestureDetector!!.onTouchEvent(event)
        return super.dispatchTouchEvent(event)
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        touchEvent(event)
        return true
    }

    private fun touchEvent(event: MotionEvent?): Boolean {
        val x = event!!.x
        val y = event.y
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                downEvent(x, y)
            }
            MotionEvent.ACTION_MOVE -> {
                moveEvent(x, y)
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                upEvent(x, y)
            }
        }
        return true
    }

    private fun downEvent(x: Float, y: Float): Boolean {
        mCurX = x
        mCurY = y
        return true
    }

    private fun moveEvent(x: Float, y: Float): Boolean {
        if (mCurX != x) {
            mXDistance += (x - mCurX) * mSpeed * mScale
            mCurX = x
        }
        if (mCurY != y) {
            mYDistance += (y - mCurY) * mSpeed * mScale
            mCurY = y
        }

        if (mXDistance < -(mImageWidth - width)) {
            mXDistance = -(mImageWidth - width).toFloat()
        }
        if (mXDistance > 0) {
            mXDistance = 0f
        }

        if (mYDistance < -(mImageHeight - height)) {
            mYDistance = -(mImageHeight - height).toFloat()
        }
        if (mYDistance > 0) {
            mYDistance = 0f
        }
        postInvalidate()
        return true
    }

    private fun upEvent(x: Float, y: Float): Boolean {
        mCurX = -1f
        mCurY = -1f
        return true
    }

    private fun postDraw() {
        if (mDecoder != null) {
            mRect.left = ((-mXDistance) + paddingLeft).toInt()
            mRect.top = (paddingTop + (-mYDistance)).toInt()
            mRect.right = (width - paddingRight + (-mXDistance)).toInt()
            mRect.bottom = (height - paddingBottom + (-mYDistance)).toInt()
            bitmap = mDecoder!!.decodeRegion(mRect, options)
            val matrix = Matrix()
            matrix.setScale(mScale, mScale)
            val w = bitmap!!.width
            val h = bitmap!!.height
            bitmap = Bitmap.createBitmap(bitmap!!, 0, 0, w, h, matrix, true)
        }
    }

    @SuppressLint("DrawAllocation")
    override fun onDraw(canvas: Canvas?) {
        postDraw()
        if (bitmap != null) {
            canvas!!.drawBitmap(bitmap!!, 0f, 0f, null)
        }
    }
}